/* Sprig: IC-7410 Rig Control Program */
/* version 0.002, Jan. 02, 2015 */
/* (c) JH1OOD, Mike */

#define NO_DEBUG
#define NO_MARKER
#define NFFT					    4096
#define WINDOW_XSIZE			1300
#define WINDOW_YSIZE			 700
#define WATERFALL_XSIZE		128
#define WATERFALL_YSIZE		128
#define WAVEFORM_LEN			 128
#define MYRIG				    	"/dev/ttyUSB0"
#define BAUDRATE			   	B19200
#define TIMEOUT_VALUE			200
#define END_OF_COMMAND		  0xfd
#define M_PI					     3.141592653589793

#include "asoundlib.h"
#include <cairo.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <gtk/gtk.h>
#include <math.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fftw3.h>
#include <complex.h>

static char *device 			= "hw:2,0"; /* playback device is IC-7410 */
static unsigned int rate 		= 32000;	/* stream rate */
static unsigned int channels 	= 1;		/* count of channels */
static int byte_per_sample 		= 2;		/* 16 bit format */
static unsigned int buffer_time = 500000;	/* ring buffer length in us */
static unsigned int period_time = 200000;	/* period time in us */
static int resample 			= 0;		/* disable resample */
static int period_event 		= 0;		/* produce poll event after each period */
static double audio_signal      [NFFT];
static double audio_signal_ffted[NFFT];
static double fft_window        [NFFT];
static double waterfall         [WATERFALL_YSIZE][WATERFALL_XSIZE];
static int cw_pitch = 600;
static int iwater = 0;
static int nsamples;
static double bin_size;

GtkWidget *button2dim[100][100];

double *in;
fftw_complex *out;
fftw_plan p;

static snd_pcm_sframes_t buffer_size;
static snd_pcm_sframes_t period_size;

double
colormap_r (double tmp)
{
  if (tmp < 0.5) return 0.0;
  if (tmp > 0.75) return 1.0;
  return (4.0 * tmp - 2.0);
}

double
colormap_g (double tmp)
{
  if (tmp < 0.25) return (4.0 * tmp);
  if (tmp > 0.75) return (-4.0 * tmp + 4.0);
  return 1.0;
}

double
colormap_b (double tmp)
{
  if (tmp < 0.25) return 1.0;
  if (tmp > 0.50) return 0.0;
  return (-4.0 * tmp + 2.0);
}

static int
set_hwparams (snd_pcm_t * handle, snd_pcm_hw_params_t * params)
{
  unsigned int rrate;
  snd_pcm_uframes_t size;
  int err, dir;

  /* choose all parameters */
  err = snd_pcm_hw_params_any (handle, params);
  if (err < 0) {
		fprintf (stderr, "Broken configuration for playback: no configurations available: %s\n", snd_strerror (err));
		return err;
  }

  /* set hardware resampling disabled */
  err = snd_pcm_hw_params_set_rate_resample (handle, params, resample);
  if (err < 0) {
		fprintf (stderr, "Resampling setup failed for playback: %s\n", snd_strerror (err)); return err;
  }

  /* set the interleaved read/write format */
  err = snd_pcm_hw_params_set_access (handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
  if (err < 0) {
		fprintf (stderr, "Access type not available for playback: %s\n", snd_strerror (err));
		return err;
  }

  /* set the sample format */
  err = snd_pcm_hw_params_set_format (handle, params, SND_PCM_FORMAT_S16);
  if (err < 0) {
		fprintf (stderr, "Sample format not available for playback: %s\n", snd_strerror (err));
		return err;
  }

  /* set the count of channels */
  err = snd_pcm_hw_params_set_channels (handle, params, channels);
  if (err < 0) {
		fprintf (stderr, "Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror (err));
		return err;
  }

  /* set the stream rate */
  rrate = rate;
  err = snd_pcm_hw_params_set_rate_near (handle, params, &rrate, 0);
  if (err < 0) {
		fprintf (stderr, "Rate %iHz not available for playback: %s\n", rate, snd_strerror (err));
		return err;
  }
  if (rrate != rate) {
		fprintf (stderr, "Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
		return -EINVAL;
  }

  /* set the buffer time */
  err = snd_pcm_hw_params_set_buffer_time_near (handle, params, &buffer_time, &dir);
  if (err < 0) {
		fprintf (stderr, "Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror (err));
		return err;
  }
  fprintf (stderr, "buffer_time = %8d, dir	 = %d \n", buffer_time, dir);

  err = snd_pcm_hw_params_get_buffer_size (params, &size);
  if (err < 0) {
		fprintf (stderr, "Unable to get buffer size for playback: %s\n", snd_strerror (err));
		return err;
  }
  buffer_size = size;
  fprintf (stderr, "buffer_size = %8d			  \n", (int) buffer_size);

  /* set the period time */
  err = snd_pcm_hw_params_set_period_time_near (handle, params, &period_time, &dir);
  if (err < 0) {
		fprintf (stderr, "Unable to set period time %i for playback: %s\n", period_time, snd_strerror (err));
		return err;
  }
  fprintf (stderr, "period_time = %8d, dir	 = %d \n", period_time, dir);

  err = snd_pcm_hw_params_get_period_size (params, &size, &dir);
  if (err < 0) {
		fprintf (stderr, "Unable to get period size for playback: %s\n", snd_strerror (err));
		return err;
  }
  period_size = size;
  fprintf (stderr, "period_size = %8d, dir	 = %d \n", (int) period_size, dir);

  if (period_size < NFFT) {
		fprintf (stderr, "error: period_size = %8d, but less than NFFT	= %d \n", (int) period_size, NFFT);
		exit (1);
  }

  /* write the parameters to device */
  err = snd_pcm_hw_params (handle, params);
  if (err < 0) {
		fprintf (stderr, "Unable to set hw params for playback: %s\n", snd_strerror (err));
		return err;
  }

  return 0;
}

static int
set_swparams (snd_pcm_t * handle, snd_pcm_sw_params_t * swparams)
{
  int err;

  /* get the current swparams */
  err = snd_pcm_sw_params_current (handle, swparams);
  if (err < 0) {
		fprintf (stderr, "Unable to determine current swparams for playback: %s\n", snd_strerror (err));
		return err;
  }

  /* start the transfer when the buffer is almost full: */
  /* (buffer_size / avail_min) * avail_min */
  err = snd_pcm_sw_params_set_start_threshold (handle, swparams, (buffer_size / period_size) * period_size);
  if (err < 0) {
		fprintf (stderr, "Unable to set start threshold mode for playback: %s\n", snd_strerror (err));
		return err;
  }

  /* allow the transfer when at least period_size samples can be processed */
  /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
  err = snd_pcm_sw_params_set_avail_min (handle, swparams, period_event ? buffer_size : period_size);
  if (err < 0) {
		fprintf (stderr, "Unable to set avail min for playback: %s\n", snd_strerror (err));
		return err;
  }

  /* enable period events when requested */
  if (period_event) {
		err = snd_pcm_sw_params_set_period_event (handle, swparams, 1);
		if (err < 0) {
		  fprintf (stderr, "Unable to set period event: %s\n", snd_strerror (err));
		  return err;
		}
  }

  /* write the parameters to the playback device */
  err = snd_pcm_sw_params (handle, swparams);
  if (err < 0) {
		fprintf (stderr, "Unable to set sw params for playback: %s\n", snd_strerror (err));
		return err;
  }
  return 0;
}

static void
async_callback (snd_async_handler_t * ahandler)
{
  snd_pcm_t    *handle  = snd_async_handler_get_pcm (ahandler);
  signed short *samples = snd_async_handler_get_callback_private (ahandler);
  snd_pcm_sframes_t avail;
  int err;

  avail = snd_pcm_avail_update (handle);

  while (avail >= period_size) {
		err = snd_pcm_readi (handle, samples, period_size);
		if (err < 0) {
		  fprintf (stderr, "Write error: %s\n", snd_strerror (err));
		  exit (EXIT_FAILURE);
		}
		if (err != period_size) {
		  fprintf (stderr, "Write error: written %i expected %li\n", err,
						   period_size);
		  exit (EXIT_FAILURE);
		}

		for (int i = 0; i < NFFT; i++) {
		  audio_signal[i] = samples[i];
#ifdef MARKER
		  audio_signal[i] +=
				16384.0 * (0.25 * sin (2.0 * 3.14 * 600.0 * (double) i / rate)
								   + 0.25 * sin (2.0 * 3.14 * 500.0 * (double) i / rate)
								   + 0.25 * sin (2.0 * 3.14 * 450.0 * (double) i / rate)
								   + 0.25 * sin (2.0 * 3.14 * 750.0 * (double) i / rate));
#endif

		}
/*
				write_count = nsamples;
				wc = write(1, samples, write_count);
				if(wc != write_count) {
						fprintf(stderr,"file write error. \n");
				}
*/

		avail = snd_pcm_avail_update (handle);
  }
}

static int
async_loop (snd_pcm_t * handle, signed short *samples)
{
  snd_async_handler_t *ahandler;
  int err;

  err = snd_async_add_pcm_handler (&ahandler, handle, async_callback, samples);
  if (err < 0) {
		fprintf (stderr, "Unable to register async handler\n");
		exit (EXIT_FAILURE);
  }

  if (snd_pcm_state (handle) == SND_PCM_STATE_PREPARED) {
		err = snd_pcm_start (handle);
		if (err < 0) {
		  fprintf (stderr, "Start error: %s\n", snd_strerror (err));
		  exit (EXIT_FAILURE);
		}
  }

  return 0;
}

void set_freq (long int ifreq_in_hz);

long int ifreq_in_hz = 7026000;
int s_meter;
int operating_mode   = 3;	/* CW=03, CW-REV=07 */
int dsp_filter       = 1;	/* FIL1=01, FIL2=02, FIL3=03 */
int fd = -1;

int
mystrlen (unsigned char *string)
{
  unsigned char *t;
  for (t = string; *t != END_OF_COMMAND; t++) {
  	;
  }
  return (t - string) + 1;	/* +1 to include EOC */
}

int
mystrcmp (unsigned char *string1, unsigned char *string2)
{
  unsigned char *t1;
  unsigned char *t2;

  for (t1 = string1, t2 = string2; *t1 == *t2 && *t1 != END_OF_COMMAND; t1++, t2++) {
  	;
  }
  return *t1 - *t2;
}

gboolean
receive_fb (void)
{
  unsigned char response[256];
  unsigned char fb_message[6] = { 0xfe, 0xfe, 0xe0, 0x80, 0xfb, 0xfd };
  int n;

  n = read (fd, response, 255); /* get echo back */

  if (mystrcmp (response, fb_message) != 0) {
		g_print ("*** error *** not a FB message. ");
		for (int i = 0; i < n; i++) {
		  g_print ("%02x ", response[i]);
		}
		g_print ("\n");
		return FALSE;
  }

  return TRUE;
}

gboolean
send_command (unsigned char *command)
{
  int n_command;
  int n_echoback, n_echoback2;
  unsigned char echoback[256], echoback2[256];

  n_command = mystrlen (command);
  write (fd, command, n_command);

  n_echoback = read (fd, echoback, 255);			/* get echo back */
  if (echoback[n_echoback - 1] == 0x0a) {			/* 0x0a now treated as EOL */
		n_echoback2 = read (fd, echoback2, 255);	/* get the rest */
		for (int i = 0; i < n_echoback2; i++) {
		  echoback[n_echoback + i] = echoback2[i];
		}
		n_echoback += n_echoback2;
  }

#ifdef DEBUG
  unsigned char *s;
  s = command;
  g_print ("send_command: n_command	 = %2d, command	 = ", n_command);
  for (int i = 0; i < n_command; i++) {
		g_print ("[%02x] ", *s++);
  }
  g_print ("\n");
  g_print ("			  n_echoback = %2d, echoback = ", n_echoback);
  s = echoback;
  for (int i = 0; i < n_echoback; i++) {
		g_print ("[%02x] ", *s++);
  }
  g_print ("\n");
#endif

  if ((n_echoback != n_command) || (mystrcmp (command, echoback) != 0)) {
		g_print ("				*** error *** echoback does not much. \n");
		return FALSE;
  }

  return TRUE;
}


int
freq_digit_pos (int ix)
{
/* cairo_move_to(cr,  4.0+28.0*i,0);  */
/* cairo_move_to(cr,157.0+28.0*i,0);  */

  int index;

  if (ix >= 0 && ix <= 144) {
		index = 7 - (ix -   4) / 28;
  } else if (ix >= 157 && ix <= 241) {
		index = 2 - (ix - 157) / 28;
  } else {
		index = -1;
  }
  return index;
}

static gboolean
cb_mouse_event (GtkWidget * widget, GdkEventScroll * event, gpointer data)
{
  double ifreq_delta;
  int ix, index;

  g_print ("mouse scroll event at (%d, %d) with direction = %d \n", (int) event->x, (int) event->y, event->direction);

  ix = (int) event->x;

  /* mouse event in waterfall area */

  int x0 = 800;
  if (ix > x0 && ix < x0 + 512) {
		ifreq_delta = (ix - x0) / 3.0 * 2.0 * bin_size - cw_pitch;
		if (operating_mode == 0x03) {	/* CW */
		  ifreq_in_hz -= ifreq_delta;
		}
		if (operating_mode == 0x07) {	/* CW-R */
		  ifreq_in_hz += ifreq_delta;
		}
		fprintf (stderr, "new frequency is %ld \n", ifreq_in_hz);
		set_freq (ifreq_in_hz);
		return FALSE;
  }

/* mouse event on frequency display	  */
/* cairo_move_to(cr,  4.0+28.0*i,0);  */
/* cairo_move_to(cr,157.0+28.0*i,0);  */

  if (ix >= 4 && ix <= 4 + 5 * 28) {
		index = 7 - (ix -   4) / 28;
  } else if (ix >= 157 && ix <= 157 + 3 * 28) {
		index = 2 - (ix - 157) / 28;
  } else {
		index = -1;
  }

  if (index < 0) {
		ifreq_delta = 0.0;
  } else {
		ifreq_delta = pow (10.0, (double) index);
  }

  if ((event->direction) == 0) {
		ifreq_delta = -ifreq_delta;
  }

  if ((ifreq_in_hz + ifreq_delta >= 0)
		  && (ifreq_in_hz + ifreq_delta < 60000000)) {
		ifreq_in_hz += ifreq_delta;
  }

  set_freq (ifreq_in_hz);
  return FALSE;
}

gboolean
timeout (gpointer data)
{
  GtkWidget *widget = GTK_WIDGET (data);
  if (!widget->window)
		return TRUE;
  gtk_widget_queue_draw (widget);
  return TRUE;
}

gboolean
configure (GtkWidget * widget, GdkEventConfigure * event, gpointer data)
{
  return TRUE;
}

gboolean
expose (GtkWidget * widget, GdkEventExpose * event, gpointer data)
{
  int x, y, width, height;

  x = event->area.x;
  y = event->area.y;
  width  = event->area.width;
  height = event->area.height;

  cairo_t *cr = gdk_cairo_create (widget->window);
  cairo_pattern_t *pattern;

  cairo_rectangle (cr, x, y, width, height);
  cairo_clip (cr);

/* s-meter */

  double x0 = 350;
  double y0 = height * 0.8;
  double ss = height * 0.65;
  double th = (2.0 * 3.14 / 360.0) * (180.0 + 30.0 + 120.0 * s_meter / 255.0);
  double xx = x0 + ss * cos (th);
  double yy = y0 + ss * sin (th);

  pattern = cairo_pattern_create_linear (x0 - ss, 0.1 * height, x0 - ss, 0.9 * height);
  cairo_pattern_add_color_stop_rgb (pattern, 0.0, 0.2, 0.2, 1.0);
  cairo_pattern_add_color_stop_rgb (pattern, 1.0, 0.8, 0.8, 1.0);
  cairo_rectangle     (cr, x0 - ss, 0.1 * height, 2.0 * ss, 0.8 * height);
  cairo_set_source    (cr, pattern);
  cairo_fill_preserve (cr);

  cairo_set_source_rgb (cr, 0.0, 0.1, 1.0);
  cairo_stroke (cr);

  cairo_set_source_rgb (cr, 0xdc / 255.0, 0x14 / 255.0, 0x3c / 255.0);
  cairo_set_line_width (cr, 4.0);
  cairo_set_line_cap   (cr, CAIRO_LINE_CAP_ROUND);
  cairo_move_to        (cr, x0, y0);
  cairo_line_to        (cr, xx, yy);
  cairo_stroke         (cr);

/* audio signal waveform */

  x0 = 400;
  cairo_set_source_rgb (cr, 0x22 / 255.0, 0x8b / 255.0, 0x22 / 255.0);
  cairo_set_line_width (cr, 2.0);
  for (int i = 0; i < WAVEFORM_LEN; i++) {
		cairo_line_to (cr, x0 + i, height * 0.5 + height * 0.4 * audio_signal[2 * i + NFFT / 2] / 32768.0);
  }
  cairo_stroke (cr);

  cairo_set_source_rgb (cr, 0x80 / 255.0, 0x80 / 255.0, 0x80 / 255.0);
  cairo_set_line_width (cr, 1.0);
  cairo_move_to (cr, x0, height * 0.5 + 0.5);
  cairo_line_to (cr, x0 + WAVEFORM_LEN, height * 0.5 + 0.5);
  cairo_stroke (cr);

/* audio signal FFT */

  for (int i = 0; i < NFFT; i++) {
		in[i] = fft_window[i] * audio_signal[i];
  }

  fftw_execute (p);

  double aval;
  for (int i = 0; i < NFFT / 4; i++) {
		aval = out[i][0] * out[i][0] + out[i][1] * out[i][1];
		if (aval < 1.0e-9) {
		  aval = -9.0;
		} else {
		  aval = log10 (out[i][0] * out[i][0] + out[i][1] * out[i][1]);
		}
		audio_signal_ffted[i] = aval;
  }

/* spectrum bar graph */

  x0 = 580;
  int hlen;
  double fmin = 300.0;
  double fmax = 900.0;
  int ibinmin = fmin / bin_size;
  int ibinmax = fmax / bin_size;

  cairo_set_source_rgb (cr, 0x00 / 255.0, 0x00 / 255.0, 0x00 / 255.0);
  cairo_move_to (cr, x0 + ((int) (cw_pitch / bin_size) - ibinmin) * 2 + 0.5, height - 9);
  cairo_line_to (cr, x0 + ((int) (cw_pitch / bin_size) - ibinmin) * 2 + 0.5, 3);
  cairo_stroke  (cr);

  for (int ifreq = 450; ifreq <= 750; ifreq += 50) {
		cairo_move_to (cr, x0 + ((int) (ifreq / bin_size) - ibinmin) * 2 + 0.5, height - 3);
		cairo_line_to (cr, x0 + ((int) (ifreq / bin_size) - ibinmin) * 2 + 0.5, height - 6);
		cairo_stroke  (cr);
  }

  double amin =  7.0;
  double amax = 14.0;
  double tmp;
  cairo_set_source_rgb (cr, 0xff / 255.0, 0x00 / 255.0, 0x00 / 255.0);
  cairo_set_line_width (cr, 1.0);
  for (int i = ibinmin; i < ibinmax; i++) {
		tmp = audio_signal_ffted[i];
		if (tmp > amax)
		  tmp = amax;
		if (tmp < amin)
		  tmp = amin;
		tmp = (tmp - amin) / (amax - amin);
		hlen = (height - 6) * tmp;
		cairo_line_to (cr, x0 + (i - ibinmin) * 2, height - 3 - hlen);
  }
  cairo_stroke (cr);

/* waterfall */

  x0 = 800;
  int ix_extend1 = 2;
  int ix_extend2 = 3;
  for (int j = 0; j < WATERFALL_XSIZE; j++) {
		tmp = audio_signal_ffted[ix_extend1 * j];
		if (tmp > amax)
		  tmp = amax;
		if (tmp < amin)
		  tmp = amin;
		tmp = (tmp - amin) / (amax - amin);
		waterfall[iwater][j] = tmp;
  }

  cairo_set_line_width (cr, 1.0);
  for (int i = 0; i < height; i++) {
		int iwatermove = iwater - i;
		while (iwatermove < 0) {
		  iwatermove += WATERFALL_YSIZE;
		}
		for (int j = 0; j < WATERFALL_XSIZE; j++) {
		  double tmp = waterfall[iwatermove][j];
		  cairo_set_source_rgb (cr, colormap_r (tmp), colormap_g (tmp), colormap_b (tmp));
		  cairo_rectangle (cr, x0 + ix_extend2 * j, i, 3, 1);
		  cairo_stroke (cr);
		}
  }
  iwater++;
  if (iwater >= WATERFALL_YSIZE)
		iwater = 0;

  cairo_set_source_rgb (cr, 0x00 / 255.0, 0x00 / 255.0, 0x00 / 255.0);
  cairo_move_to (cr, (int) (x0 + (cw_pitch / bin_size) * ((double) ix_extend2 / (double) ix_extend1)) + 0.5, 5);
  cairo_line_to (cr, (int) (x0 + (cw_pitch / bin_size) * ((double) ix_extend2 / (double) ix_extend1)) + 0.5, height - 5);
  cairo_stroke (cr);

/* frequency display */

  char string[128];
  cairo_set_source_rgb (cr, 0.0, 0.1, 1.0);
  cairo_select_font_face (cr, "FreeSans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);

  cairo_set_font_size (cr, 50.0);
  if (ifreq_in_hz >= 10000000) {		/* higher than 10MHz */
		sprintf (string, "%9.3f", ((double) ifreq_in_hz) / 1000.0);
		cairo_move_to (cr, 4.0, height - 6.0);
  } else {
		sprintf (string, "%8.3f", ((double) ifreq_in_hz) / 1000.0);
		cairo_move_to (cr, 32.0, height - 6.0);
  }
  cairo_show_text (cr, string);

  cairo_set_font_size (cr, 20.0);
  cairo_move_to       (cr, 250.0, height - 6.0);
  cairo_show_text     (cr, "kHz");

/*
		cairo_set_line_width(cr,1.0);
		cairo_set_source_rgb(cr,0.5,1.0,0.5);
		for(int i=0;i<6;i++) {
				cairo_move_to(cr,4.0+28.0*i,0);
				cairo_line_to(cr,4.0+28.0*i,height);
				cairo_stroke(cr);
		}
		for(int i=0;i<4;i++) {
				cairo_move_to(cr,157.0+28.0*i,0);
				cairo_line_to(cr,157.0+28.0*i,height);
				cairo_stroke(cr);
		}
*/

  cairo_set_source_rgb (cr, 0, 0, 0);
  cairo_destroy        (cr);

  return FALSE;
}

void
serial_init (void)
{
  struct termios tio;
  memset (&tio, 0, sizeof (tio));
  tio.c_cflag     = CS8 | CLOCAL | CREAD;
  tio.c_cc[VTIME] = 0;
  tio.c_cc[VEOL]  = 0xfd;				/* IC-7410 postamble */
  tio.c_lflag     = ICANON;
  tio.c_iflag     = IGNPAR | ICRNL;
  cfsetispeed (&tio, BAUDRATE);
  cfsetospeed (&tio, BAUDRATE);
  tcsetattr (fd, TCSANOW, &tio);
}

void
set_freq (long int ifreq_in_hz)
{
  g_print ("freq set to %12.3f [kHz] \n", (double) ifreq_in_hz / 1000.0);
  static unsigned char command1[11] = { 0xfe, 0xfe, 0x80, 0xe0, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd };
  long int ifreq_wrk;
  int idigit[8];

  ifreq_wrk = ifreq_in_hz;

  for (int i = 0; i < 8; i++) {
		idigit[i] = ifreq_wrk % 10;
		ifreq_wrk /= 10;
  }
  command1[5] = 16 * idigit[1] + idigit[0];
  command1[6] = 16 * idigit[3] + idigit[2];
  command1[7] = 16 * idigit[5] + idigit[4];
  command1[8] = 16 * idigit[7] + idigit[6];
  send_command (command1);
  receive_fb ();
}

void
set_tx_power (int txpower)
{
  static unsigned char command1[9] = { 0xfe, 0xfe, 0x80, 0xe0, 0x14, 0x0a, 0x00, 0x32, 0xfd };
  int iii, i100, i10, i1;

  if (txpower < 2)
		txpower = 2;
  if (txpower > 100)
		txpower = 100;
  iii  = 255.0 * (txpower - 2) / 100.0;
  i100 = iii / 100;
  i10  = (iii - 100 * i100) / 10;
  i1   = iii % 10;
  g_print ("txpower changed %d %d %d %d \n", txpower, i100, i10, i1);
  command1[6] = i100;
  command1[7] = 16 * i10 + i1;
  send_command (command1);
  receive_fb ();
}

void
set_operating_mode (void)
{
  static unsigned char command1[8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x06, 0x03, 0x01, 0xfd };

  command1[5] = operating_mode;
  command1[6] = dsp_filter;;
  send_command (command1);
  receive_fb ();
}

void
set_cw_pitch (int pitch)
{
  static unsigned char command1[9] = { 0xfe, 0xfe, 0x80, 0xe0, 0x14, 0x09, 0x00, 0x32, 0xfd };
  int iii, i100, i10, i1;

  if (pitch < 300)
		pitch = 300;
  if (pitch > 900)
		pitch = 900;
  cw_pitch = pitch;
  iii  = 128 + 127.0 * (pitch - 600) / 300.0;
  i100 = iii / 100;
  i10  = (iii - 100 * i100) / 10;
  i1   = iii % 10;
  g_print ("pitch changed %d %d %d %d \n", pitch, i100, i10, i1);
  command1[6] = i100;
  command1[7] = 16 * i10 + i1;
  send_command (command1);
  receive_fb ();
}

void
set_cw_speed (int wpm)
{
  static unsigned char command1[9] = { 0xfe, 0xfe, 0x80, 0xe0, 0x14, 0x0c, 0x00, 0x32, 0xfd };
  int iii, i100, i10, i1;

  if (wpm < 6)
		wpm = 6;
  if (wpm > 48)
		wpm = 48;
  iii  = 255 * (wpm - 6) / (48 - 6);
  i100 = iii / 100;
  i10  = (iii - 100 * i100) / 10;
  i1   = iii % 10;
  g_print ("wpm changed %d %d %d %d \n", wpm, i100, i10, i1);
  command1[6] = i100;
  command1[7] = 16 * i10 + i1;
  send_command (command1);
  receive_fb ();
}

void
scale_value_changed2 (GtkWidget * scale, gpointer data)
{																/* Key Speed Slider */
  int wpm;

  wpm = gtk_range_get_value (GTK_RANGE (scale));
  g_print ("wpm changed %d \n", wpm);
  set_cw_speed (wpm);
}

void
scale_value_changed3 (GtkWidget * scale, gpointer data)
{																/* CW Pitch */
  int pitch;
  pitch = gtk_range_get_value (GTK_RANGE (scale));
  g_print ("CW pitch changed %d \n", pitch);
}

void
scale_value_changed1 (GtkWidget * scale, gpointer data)
{																/* AF Volume Slider */
  static unsigned char command1[9] = { 0xfe, 0xfe, 0x80, 0xe0, 0x14, 0x01, 0x00, 0x32, 0xfd };
  int value, i100, i10, i1;

  value = gtk_range_get_value (GTK_RANGE (scale));
  i100  = value / 100;
  i10   = (value - 100 * i100) / 10;
  i1    = value % 10;
  g_print ("value changed %d %d %d %d \n", value, i100, i10, i1);
  command1[6] = i100;
  command1[7] = 16 * i10 + i1;
  send_command (command1);
  receive_fb ();
}

void
callback3 (GtkWidget * widget, gpointer data)
{
  char s[100];
  int n;
  double freq_in_khz;

  n = strlen ((char *) data);
  strncpy (s, (char *) data, strlen ((char *) data) - 3);
  s[n - 3] = '\0';
  freq_in_khz = atof (s);
  g_print ("callback3: %s was toggled %d [%s] %f \n", (char *) data, n, s, freq_in_khz);
  ifreq_in_hz = freq_in_khz * 1000.0;
  set_freq (ifreq_in_hz);
}

gboolean
myclock (gpointer data)
{
  static unsigned char command1[6] = { 0xfe, 0xfe, 0x80, 0xe0, 0x03, 0xfd };
  static unsigned char command2[7] = { 0xfe, 0xfe, 0x80, 0xe0, 0x15, 0x02, 0xfd };
  static unsigned char command3[7] = { 0xfe, 0xfe, 0x80, 0xe0, 0x04, 0xfd };
  char          string[256];
  unsigned char buf   [255];
  int res;

/* read operating mode, response in char[5]-char[6] */

  send_command (command3);
  res = read (fd, buf, 255);
  if (res != 8) {
		g_print ("operating mode response is wrong! \n");
  }
  operating_mode = buf[5];
  dsp_filter = buf[6];
  if (operating_mode == 0x03) { /* CW */
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button2dim[0][0]), TRUE);
  }
  if (operating_mode == 0x07) { /* CW-R */
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button2dim[0][1]), TRUE);
  }
  if (dsp_filter == 0x01) {				/* FIL1 */
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button2dim[6][0]), TRUE);
  }
  if (dsp_filter == 0x02) {				/* FIL2 */
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button2dim[6][1]), TRUE);
  }
  if (dsp_filter == 0x03) {				/* FIL3 */
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button2dim[6][2]), TRUE);
  }

/* freq response in char[8]-char[5] */

  send_command (command1);
  res = read (fd, buf, 255);

#ifdef DEBUG
  unsigned char *s;
  g_print ("response for frequncy read, res = %2d : ", res);
  s = buf;
  for (int i = 0; i < res; i++) {
		g_print ("[%02x] ", *s++);
  }
  g_print ("\n");
#endif

  if (res != 11) {
		g_print ("frequency response is wrong! \n");
  }
  sprintf (string, "%02x%02x%02x%02x", buf[8], buf[7], buf[6], buf[5]);
  ifreq_in_hz = atoi (string);

/* S-meter response in char[6]-char[5] */

  send_command (command2);
  res = read (fd, buf, 255);
  if (res != 9) {
		g_print ("S-meter response is wrong! \n");
  }

  sprintf (string, "%02x%02x", buf[6], buf[7]);
  s_meter = atoi (string);

  return TRUE;
}

void
callback2 (GtkWidget * widget, gpointer data)
{
  static unsigned char command3 [8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x47, 0x00, 0xfd };		/* BKIN OFF	 */
  static unsigned char command4 [8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x47, 0x01, 0xfd };		/* BKIN ON	 */
  static unsigned char command5 [8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x47, 0x02, 0xfd };		/* BKIN FULL */
  static unsigned char command6 [8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x55, 0x00, 0xfd };		/* IF FIL1 */
//static unsigned char command7 [8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x55, 0x01, 0xfd};		/* if fil2 */
  static unsigned char command8 [8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x55, 0x02, 0xfd };		/* IF FIL3 */
  static unsigned char command19[8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x56, 0x00, 0xfd };		/* DSP SHARP */
  static unsigned char command20[8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x56, 0x01, 0xfd };		/* DSP SOFT */
  static unsigned char command9 [8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x02, 0x00, 0xfd };		/* PRE-AMP OFF */
  static unsigned char command10[8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x02, 0x01, 0xfd };		/* PRE-AMP 1  */
  static unsigned char command11[8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x02, 0x02, 0xfd };		/* PRE-AMP 2  */
  static unsigned char command12[7] = { 0xfe, 0xfe, 0x80, 0xe0, 0x11, 0x00, 0xfd };				/* ATT OFF	*/
  static unsigned char command13[7] = { 0xfe, 0xfe, 0x80, 0xe0, 0x11, 0x20, 0xfd };				/* ATT 20dB */
  static unsigned char command14[7] = { 0xfe, 0xfe, 0x80, 0xe0, 0x12, 0x00, 0xfd };				/* ANT 1 */
  static unsigned char command15[7] = { 0xfe, 0xfe, 0x80, 0xe0, 0x12, 0x01, 0xfd };				/* ANT 2 */
  static unsigned char command16[8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x12, 0x01, 0xfd };		/* AGC FAST	 */
  static unsigned char command17[8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x12, 0x02, 0xfd };		/* AGC FAST	 */
  static unsigned char command18[8] = { 0xfe, 0xfe, 0x80, 0xe0, 0x16, 0x12, 0x03, 0xfd };		/* AGC SLOW	 */
  int wpm, pitch, txpower;

  g_print ("callback2: %s was toggled \n", (char *) data);

  if (GTK_TOGGLE_BUTTON (widget)->active) {
		g_print ("active \n");
  } else {
		g_print ("not active, do nothing and return FALSE \n");
		return;
  }

  if (g_strcmp0 ((char *) data, "CW") == 0) {
		operating_mode = 3;
		set_operating_mode ();
  }

  if (g_strcmp0 ((char *) data, "CW-REV") == 0) {
		operating_mode = 7;
		set_operating_mode ();
  }

  if (g_strcmp0 ((char *) data, "DSP FIL1") == 0) {
		dsp_filter = 1;
		set_operating_mode ();
  }

  if (g_strcmp0 ((char *) data, "DSP FIL2") == 0) {
		dsp_filter = 2;
		set_operating_mode ();
  }

  if (g_strcmp0 ((char *) data, "DSP FIL3") == 0) {
		dsp_filter = 3;
		set_operating_mode ();
  }

  if (g_strcmp0 ((char *) data, "BKIN OFF") == 0) {
		send_command (command3);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "BKIN ON") == 0) {
		send_command (command4);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "BKIN FULL") == 0) {
		send_command (command5);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "IF FIL1") == 0) {
		g_print ("IF FIL1 \n");
		send_command (command6);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "if fil2") == 0) {
		g_print ("IF FIL2 is not implemented. \n");
  }

  if (g_strcmp0 ((char *) data, "IF FIL3") == 0) {
		g_print ("IF FIL3 \n");
		send_command (command8);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "DSP SHARP") == 0) {
		g_print ("DSP SHARP \n");
		send_command (command19);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "DSP SOFT") == 0) {
		g_print ("DSP SOFT \n");
		send_command (command20);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "BOTH OFF") == 0) {
		g_print ("PRE-AMP OFF \n");
		send_command (command9);		/* PRE-AMP OFF */
		receive_fb ();
		send_command (command12);		/* ATT OFF */
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "PRE-AMP 1") == 0) {
		g_print ("PRE-AMP 1 \n");
		send_command (command10);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "PRE-AMP 2") == 0) {
		g_print ("PRE-AMP 2 \n");
		send_command (command11);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "ATT 20dB") == 0) {
		g_print ("ATT 20dB \n");
		send_command (command13);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "AGC FAST") == 0) {
		g_print ("AGC FIRST \n");
		send_command (command16);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "AGC MID") == 0) {
		g_print ("AGC MID \n");
		send_command (command17);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "AGC SLOW") == 0) {
		g_print ("AGC SLOW \n");
		send_command (command18);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "ANT 1") == 0) {
		g_print ("ANT 1 \n");
		send_command (command14);
		receive_fb ();
  }

  if (g_strcmp0 ((char *) data, "ANT 2") == 0) {
		g_print ("ANT 2 \n");
		send_command (command15);
		receive_fb ();
  }

  if (g_str_has_suffix ((char *) data, "Hz")
		  && !g_str_has_suffix ((char *) data, "kHz")) {
		pitch = atoi (g_strndup ((char *) data, 3));
		set_cw_pitch (pitch);
		g_print ("CW pitch set to %d \n", pitch);
  }

  if (g_str_has_suffix ((char *) data, "wpm")) {
		wpm = atoi (g_strndup ((char *) data, 2));
		set_cw_speed (wpm);
		g_print ("Key Speed set to %d \n", wpm);
  }

  if (g_str_has_suffix ((char *) data, " W")) {
		int n = mystrlen (data);
		txpower = atoi (g_strndup ((char *) data, n - 3));		/* delete " W"+EOC */
		set_tx_power (txpower);
		g_print ("TX power set to %d \n", txpower);
  }

  char s[100];
  int n;
  double freq_in_khz;
  if (g_str_has_suffix ((char *) data, "kHz")) {
		n = strlen ((char *) data);
		strncpy (s, (char *) data, strlen ((char *) data) - 3);
		s[n - 3] = '\0';
		freq_in_khz = atof (s);
		g_print ("freq set to  %f \n", freq_in_khz);
		ifreq_in_hz = freq_in_khz * 1000.0;
		set_freq (ifreq_in_hz);
  }

  return;

}

gint
delete_event (GtkWidget * widget, GdkEvent * event, gpointer data)
{
  gtk_main_quit ();
  return (FALSE);
}

int
main (int argc, char *argv[])
{

  struct radio_button
  {
		int nbutton;
		char name[32][128];
  };

  int ngroup = 12;
  struct radio_button my_radio_buttons[128] = {
		{2, {"CW", "CW-REV"}},
		{7, {"450Hz", "500Hz", "550Hz", "600Hz", "650Hz", "700Hz", "750Hz"}},
		{7, {"10 wpm", "15 wpm", "20 wpm", "25 wpm", "30 wpm", "35 wpm", "40 wpm"}},
		{3, {"BKIN OFF", "BKIN ON", "BKIN FULL"}},
		{6, {"2 W", "5 W", "10 W", "20 W", "50 W", "100 W"}},
		{3, {"IF FIL1", "if fil2", "IF FIL3"}},
		{3, {"DSP FIL1", "DSP FIL2", "DSP FIL3"}},
		{2, {"DSP SHARP", "DSP SOFT"}},
		{4, {"PRE-AMP 1", "PRE-AMP 2", "ATT 20dB", "BOTH OFF"}},
		{3, {"AGC FAST", "AGC MID", "AGC SLOW"}},
		{2, {"ANT 1", "ANT 2"}},
		{8, {" 3501.234kHz", " 7026.000kHz", "10118.000kHz", "14058.000kHz", "18085.000kHz", "21058.000kHz", "24908.000kHz", "28058.000kHz"}},
  };

  struct termios oldtio;

  struct mybutton
  {
		char name[100];
		int left_attach;
		int right_attach;
		int top_attach;
		int bottom_attach;
  };

  int ncolumns = 6, nrows = 3;
  int nbutton = 3;
  struct mybutton mybuttons[100] = {
		{"Function 1", 0, 1, 0, 1},
		{"Function 2", 0, 1, 1, 2},
		{"Function 3", 0, 1, 2, 3},
  };

  GtkWidget *scale1, *scale2, *scale3;
  GtkWidget *image[10];
  GtkWidget *box1, *box2, *box3, *box4, *box5, *box6, *box7, *box8, *box9;
  GtkWidget *box_mod, *box_tx;
  GtkWidget *table;
  GtkWidget *window;
  GtkWidget *button;
  GtkWidget *label;
  GtkWidget *hsep, *vsep;
  GtkObject *adj1, *adj2, *adj3;

  snd_pcm_t *handle;
  snd_pcm_hw_params_t *hwparams;
  snd_pcm_sw_params_t *swparams;
  signed short *samples;
  int err;

  bin_size = rate / (double) NFFT;
  for (int i = 0; i < NFFT; i++) {
		fft_window[i] = 0.54 - 0.46 * cos (2.0 * M_PI * i / (double) NFFT);
  }

  in  = malloc (sizeof (double) * NFFT);
  out = (fftw_complex *) fftw_malloc (sizeof (fftw_complex) * (NFFT / 2 + 1));
  p   = fftw_plan_dft_r2c_1d (NFFT, in, out, FFTW_ESTIMATE);

  snd_pcm_hw_params_alloca (&hwparams);
  snd_pcm_sw_params_alloca (&swparams);

  fprintf (stderr, "audio capture device = %s, rate = %i Hz, %i channels\n", device, rate, channels);

  if ((err = snd_pcm_open (&handle, device, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
		fprintf (stderr, "Capture open error: %s\n", snd_strerror (err));
		return 0;
  }

  if ((err = set_hwparams (handle, hwparams)) < 0) {
		fprintf (stderr, "Setting of hwparams failed: %s\n", snd_strerror (err));
		exit (EXIT_FAILURE);
  }
  if ((err = set_swparams (handle, swparams)) < 0) {
		fprintf (stderr, "Setting of swparams failed: %s\n", snd_strerror (err));
		exit (EXIT_FAILURE);
  }

  nsamples = period_size * channels * byte_per_sample;
  fprintf (stderr, "nsamples = %d \n", nsamples);
  samples = malloc (nsamples);
  if (samples == NULL) {
		fprintf (stderr, "No enough memory\n");
		exit (EXIT_FAILURE);
  }

  err = async_loop (handle, samples);

/*
		if (err < 0) fprintf(stderr,"Transfer failed: %s\n", snd_strerror(err));

		free(samples);
		snd_pcm_close(handle);
*/

  gtk_init (&argc, &argv);

  fd = open (MYRIG, O_RDWR | O_NOCTTY);
  if (fd < 0) {
		fprintf (stderr, "Error: can not open %s \n", MYRIG);
		return (-1);
  }
  tcgetattr (fd, &oldtio);
  serial_init ();

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_size_request (window, WINDOW_XSIZE, WINDOW_YSIZE);
  gtk_window_set_title (GTK_WINDOW (window), "IC-7410 Rig Control");
  gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL);
  gtk_container_set_border_width (GTK_CONTAINER (window), 20);

  box1 = gtk_vbox_new (FALSE, 5);
  box2 = gtk_hbox_new (FALSE, 5);
  gtk_widget_set_size_request (box2, 720, 200);
  box3 = gtk_vbox_new (FALSE, 5);
  box4 = gtk_vbox_new (FALSE, 5);
  box5 = gtk_vbox_new (FALSE, 5);
  box6 = gtk_vbox_new (FALSE, 5);
  box_mod = gtk_vbox_new (FALSE, 5);
  box_tx = gtk_vbox_new (FALSE, 5);
  box7 = gtk_hbox_new (FALSE, 5);
  box8 = gtk_hbox_new (FALSE, 5);
  box9 = gtk_vbox_new (FALSE, 5);

  adj1 = gtk_adjustment_new (50.0, 0.0, 256.0, 1.0, 1.0, 1.0);
  adj2 = gtk_adjustment_new (35.0, 6.0, 49.0, 1.0, 1.0, 1.0);
  adj3 = gtk_adjustment_new (50.0, 0.0, 256.0, 1.0, 1.0, 1.0);

  scale1 = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
  scale2 = gtk_vscale_new (GTK_ADJUSTMENT (adj2));
  scale3 = gtk_vscale_new (GTK_ADJUSTMENT (adj3));

  gtk_scale_set_value_pos (GTK_SCALE (scale1), GTK_POS_TOP);
  gtk_scale_set_value_pos (GTK_SCALE (scale2), GTK_POS_TOP);
  gtk_scale_set_value_pos (GTK_SCALE (scale3), GTK_POS_TOP);

  gtk_signal_connect (GTK_OBJECT (scale1), "value_changed", GTK_SIGNAL_FUNC (scale_value_changed1), NULL);
  gtk_signal_connect (GTK_OBJECT (scale2), "value_changed", GTK_SIGNAL_FUNC (scale_value_changed2), NULL);
  gtk_signal_connect (GTK_OBJECT (scale3), "value_changed", GTK_SIGNAL_FUNC (scale_value_changed3), NULL);

  label = gtk_label_new_with_mnemonic ("AF Volume");
  gtk_widget_show (label);
  gtk_box_pack_start (GTK_BOX (box3), scale1, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box3), label,  TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box2), box3,   TRUE, TRUE, 0);
  gtk_widget_show (box3);
  gtk_widget_show (box2);

  label = gtk_label_new_with_mnemonic ("Key Speed");
  gtk_widget_show (label);
  gtk_box_pack_start (GTK_BOX (box4), scale2, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box4), label,  TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box2), box4,   TRUE, TRUE, 0);
  gtk_widget_show (box4);
  gtk_widget_show (box2);

  label = gtk_label_new_with_mnemonic ("CW Pitch");
  gtk_widget_show (label);
  gtk_box_pack_start (GTK_BOX (box9), scale3, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box9), label,  TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box2), box9,   TRUE, TRUE, 0);
  gtk_widget_show (box5);
  gtk_widget_show (box2);

  table = gtk_table_new (nrows, ncolumns, TRUE);

  for (int i = 0; i < nbutton; i++) {
		button = gtk_button_new_with_label (mybuttons[i].name);
//		gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (callback), (gpointer) mybuttons[i].name);
		gtk_table_attach_defaults (GTK_TABLE (table), button, mybuttons[i].left_attach, mybuttons[i].right_attach, mybuttons[i].top_attach, mybuttons[i].bottom_attach);
		gtk_widget_show (button);
  }

/*
		GtkWidget *hbox_radio, *vbox_radio;
		hbox_radio = gtk_hbox_new(FALSE, 5);
		vsep = gtk_vseparator_new();
		gtk_box_pack_start (GTK_BOX (hbox_radio), vsep, FALSE, FALSE, 5);
		for(int j=0;j<ngroup;j++) {
				vbox_radio = gtk_vbox_new(FALSE, 5);
				for(int i=0;i<my_radio_buttons[j].nbutton;i++) {
				if(i == 0) {
								button = gtk_radio_button_new_with_label(NULL, my_radio_buttons[j].name[i]);
						} else {
								button = gtk_radio_button_new_with_label(gtk_radio_button_group (GTK_RADIO_BUTTON (button)), my_radio_buttons[j].name[i]);
						}
						gtk_signal_connect (GTK_OBJECT (button), "toggled", GTK_SIGNAL_FUNC (callback2),(gpointer) my_radio_buttons[j].name[i]);
						gtk_box_pack_start (GTK_BOX (vbox_radio), button, FALSE, FALSE, 0);
						gtk_widget_show (button);
				}
				gtk_box_pack_start (GTK_BOX (hbox_radio), vbox_radio, FALSE, FALSE, 0);
				vsep = gtk_vseparator_new();
				gtk_box_pack_start (GTK_BOX (hbox_radio), vsep, FALSE, FALSE, 5);
		}
*/

/**** test ****/

  GtkWidget *hbox_radio, *vbox_radio;
  hbox_radio = gtk_hbox_new (FALSE, 5);
  vsep = gtk_vseparator_new ();
  gtk_box_pack_start (GTK_BOX (hbox_radio), vsep, FALSE, FALSE, 5);
  for (int j = 0; j < ngroup; j++) {
		vbox_radio = gtk_vbox_new (FALSE, 5);
		for (int i = 0; i < my_radio_buttons[j].nbutton; i++) {
		  if (i == 0) {
				button2dim[j][i] = gtk_radio_button_new_with_label (NULL, my_radio_buttons[j].name[i]);
		  } else {
				button2dim[j][i] = gtk_radio_button_new_with_label (gtk_radio_button_group (GTK_RADIO_BUTTON (button2dim[j][0])), my_radio_buttons[j].name[i]);
		  }
		  gtk_signal_connect (GTK_OBJECT (button2dim[j][i]), "toggled", GTK_SIGNAL_FUNC (callback2), (gpointer) my_radio_buttons[j].name[i]);
		  gtk_box_pack_start (GTK_BOX (vbox_radio), button2dim[j][i], FALSE, FALSE, 0);
		  gtk_widget_show (button2dim[j][i]);
		}
		gtk_box_pack_start (GTK_BOX (hbox_radio), vbox_radio, FALSE, FALSE, 0);
		vsep = gtk_vseparator_new ();
		gtk_box_pack_start (GTK_BOX (hbox_radio), vsep, FALSE, FALSE, 5);
  }

  /*
	 GtkWidget *myradiobutton[100];
	 myradiobutton[0] = gtk_radio_button_new_with_label(NULL, "test0");
	 myradiobutton[1] = gtk_radio_button_new_with_label(gtk_radio_button_group (GTK_RADIO_BUTTON (myradiobutton[0])), "test1");
	 myradiobutton[2] = gtk_radio_button_new_with_label(gtk_radio_button_group (GTK_RADIO_BUTTON (myradiobutton[0])), "test2");
	 vbox_radio = gtk_vbox_new(FALSE, 5);
	 gtk_box_pack_start (GTK_BOX (vbox_radio), myradiobutton[0], FALSE, FALSE, 0);
	 gtk_box_pack_start (GTK_BOX (vbox_radio), myradiobutton[1], FALSE, FALSE, 0);
	 gtk_box_pack_start (GTK_BOX (vbox_radio), myradiobutton[2], FALSE, FALSE, 0);
	 gtk_widget_show (myradiobutton[0]);
	 gtk_widget_show (myradiobutton[1]);
	 gtk_widget_show (myradiobutton[2]);
	 gtk_box_pack_start (GTK_BOX (hbox_radio), vbox_radio, FALSE, FALSE, 0);

	 GtkWidget *myradiobutton[10][100];
	 myradiobutton[1][0] = gtk_radio_button_new_with_label(NULL, "2nd");
	 myradiobutton[1][1] = gtk_radio_button_new_with_label(gtk_radio_button_group (GTK_RADIO_BUTTON (myradiobutton[1][0])), "test1");
	 myradiobutton[1][2] = gtk_radio_button_new_with_label(gtk_radio_button_group (GTK_RADIO_BUTTON (myradiobutton[1][0])), "test2");
	 vbox_radio = gtk_vbox_new(FALSE, 5);
	 gtk_box_pack_start (GTK_BOX (vbox_radio), myradiobutton[1][0], FALSE, FALSE, 0);
	 gtk_box_pack_start (GTK_BOX (vbox_radio), myradiobutton[1][1], FALSE, FALSE, 0);
	 gtk_box_pack_start (GTK_BOX (vbox_radio), myradiobutton[1][2], FALSE, FALSE, 0);
	 gtk_widget_show (myradiobutton[1][0]);
	 gtk_widget_show (myradiobutton[1][1]);
	 gtk_widget_show (myradiobutton[1][2]);
	 gtk_box_pack_start (GTK_BOX (hbox_radio), vbox_radio, FALSE, FALSE, 0);
   */

  gtk_box_pack_start (GTK_BOX (box7), box_mod, FALSE, FALSE, 5);
  vsep = gtk_vseparator_new ();
  gtk_box_pack_start (GTK_BOX (box7), vsep, FALSE, FALSE, 5);

  gtk_box_pack_start (GTK_BOX (box7), box5, FALSE, FALSE, 5);
  vsep = gtk_vseparator_new ();
  gtk_box_pack_start (GTK_BOX (box7), vsep, FALSE, FALSE, 5);

  gtk_box_pack_start (GTK_BOX (box7), box_tx, FALSE, FALSE, 5);
  vsep = gtk_vseparator_new ();
  gtk_box_pack_start (GTK_BOX (box7), vsep, FALSE, FALSE, 5);

  gtk_box_pack_start (GTK_BOX (box7), box6, FALSE, FALSE, 5);

  button = gtk_button_new_with_label ("Quit");
  gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (delete_event), NULL);
  gtk_table_attach_defaults (GTK_TABLE (table), button, 2, 3, 1, 3);

//	  gtk_table_attach_defaults (GTK_TABLE(table), scale1, 0, 3, 4, 6);
//	  gtk_table_attach_defaults (GTK_TABLE(table), scale2, 1, 4, 6, 7);

/********************/

  GtkWidget *drawing_area;
  drawing_area = gtk_drawing_area_new ();
  const GdkColor background = { 0, 0x8700, 0xce00, 0xfa00 };
  gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &background);
  gtk_widget_set_size_request (drawing_area, 40, 50);
  g_signal_connect (drawing_area, "configure_event", G_CALLBACK (configure), NULL);
  g_signal_connect (drawing_area, "expose_event", G_CALLBACK (expose), NULL);
  g_timeout_add (TIMEOUT_VALUE, timeout, window);

/********************/

  char *fname[10] = { "/home/user1/Pictures/n0.png",
		"/home/user1/Pictures/n1.png",
		"/home/user1/Pictures/n2.png",
		"/home/user1/Pictures/n3.png",
		"/home/user1/Pictures/n4.png",
		"/home/user1/Pictures/n5.png",
		"/home/user1/Pictures/n6.png",
		"/home/user1/Pictures/n7.png",
		"/home/user1/Pictures/n8.png",
		"/home/user1/Pictures/n9.png"
  };

  for (int i = 0; i < 10; i++) {
		image[i] = gtk_image_new_from_file (fname[i]);
		gtk_box_pack_start (GTK_BOX (box8), image[i], TRUE, TRUE, 0);
		gtk_widget_show (image[i]);
  }

/********************/

  hsep = gtk_hseparator_new ();
  gtk_box_pack_start (GTK_BOX (box1), hsep, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box1), drawing_area, FALSE, FALSE, 0);
  hsep = gtk_hseparator_new ();
  gtk_box_pack_start (GTK_BOX (box1), hsep, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box1), hbox_radio, FALSE, FALSE, 5);
  gtk_box_pack_start (GTK_BOX (box1), box7, FALSE, FALSE, 5);
  gtk_box_pack_start (GTK_BOX (box1), table, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (box1), box8, TRUE, TRUE, 0);
  hsep = gtk_hseparator_new ();
  gtk_box_pack_start (GTK_BOX (box1), hsep, TRUE, TRUE, 0);
  gtk_container_add (GTK_CONTAINER (window), box1);

/**********/

  gtk_widget_add_events (drawing_area, GDK_SCROLL_MASK);
  g_signal_connect (G_OBJECT (drawing_area), "scroll-event", G_CALLBACK (cb_mouse_event), NULL);
  gtk_widget_show_all (window);

  g_timeout_add (TIMEOUT_VALUE, (GSourceFunc) myclock, (gpointer) "abc");
  gtk_main ();

  gdk_threads_leave ();

  fftw_destroy_plan (p);
  fftw_free (in);
  fftw_free (out);

  return 0;
}
